package com.bjsxt.aspect;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.bjsxt.domain.SysUserLog;
import com.bjsxt.model.WebLog;
import com.bjsxt.service.SysUserLogService;
import com.bjsxt.util.IpUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.annotation.Order;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @version 1.0
 * @author xen
 * @date 2021/7/13 - 17:00
 */
@Aspect
@Order(2)
@Slf4j
public class WebLogAdminAspect {

    @Autowired
    private SysUserLogService sysUserLogService;

    /**
     * 雪花算法
     * 1. 机器ID
     * 2. 应用ID
     */
    private Snowflake snowflake = new Snowflake(1, 1);

    /**
     * 定义切入点
     */
    @Pointcut("execution(* com.bjsxt.controller.*.*(..))")
    public void webLogAdminAspect() { }

    /**
     * 记录环绕日志通知
     * 方法执行之前、之后
     */
    @Around("webLogAdminAspect()")
    public Object recodeWebLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object result = null;
        WebLog webLog = new WebLog();
        // 开始时间
        long startTime = System.currentTimeMillis();
        // 执行方法的真实调用
        result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
        // 结束时间
        long endTime = System.currentTimeMillis();
        webLog.setSpendTime((int)(endTime - startTime));
        // 获取当前请求的request对象
        ServletRequestAttributes servletRequestAttributes =
                (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert servletRequestAttributes != null;
        HttpServletRequest request = servletRequestAttributes.getRequest();

        String url = request.getRequestURL().toString();
        String uri = request.getRequestURI();
        webLog.setUrl(url);
        webLog.setUri(uri);
        webLog.setBasePath(StrUtil.removeSuffix(url, URLUtil.getPath(url)));
        webLog.setIp(IpUtil.getIpAddr(request));

        // 获取安全上下文
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        webLog.setUsername(authentication == null ? "anonymous" : authentication.getPrincipal().toString());

        // 获取方法
        MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
        Method method = methodSignature.getMethod();
        // 获取类的名称
        String targetClassName = proceedingJoinPoint.getTarget().getClass().getName();

        // 因为我们会使用Swagger 这工具，我们必须在方法上面添加@ApiOperation(value="")该注解
        // 获取ApiOperation
        ApiOperation apiOperationAnnotation = method.getAnnotation(ApiOperation.class);
        webLog.setDescription(apiOperationAnnotation == null ? "no desc" : apiOperationAnnotation.value());
        webLog.setMethod(targetClassName + "." + method.getName());
        webLog.setParameter(getMethodParameter(method, proceedingJoinPoint.getArgs()));
        webLog.setResult(result);

        SysUserLog sysUserLog = new SysUserLog();
        sysUserLog.setId(snowflake.nextId());
        sysUserLog.setCreated(new Date());
        sysUserLog.setDescription(webLog.getDescription());
        sysUserLog.setGroup(webLog.getDescription());
        sysUserLog.setUserId(Long.valueOf(webLog.getUsername()));
        sysUserLog.setMethod(webLog.getMethod());
        sysUserLog.setIp(sysUserLog.getIp());
        sysUserLogService.save(sysUserLog) ;
        
        return result;
    }

    /**
     * 获取方法的执行参数
     * @param method  方法
     * @param args    参数
     * @return methodParamWithValues
     */
    private Object getMethodParameter(Method method, Object[] args) {
        Map<String, Object> methodParamWithValues = new HashMap<>();

        LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer =
                new LocalVariableTableParameterNameDiscoverer();

        // 方法的形参名称
        String[] parameterNames = localVariableTableParameterNameDiscoverer.getParameterNames(method);
        assert parameterNames != null && parameterNames.length > 0;
        for (int i = 0; i < parameterNames.length; i++) {
            if("password".equals(parameterNames[i]) || "file".equals(parameterNames[i])) {
                methodParamWithValues.put(parameterNames[i],"受限的支持类型") ;
            } else {
                methodParamWithValues.put(parameterNames[i],args[i]) ;
            }
        }
        return methodParamWithValues;
    }
}
